package com.base.andlang2.apollo

import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.Mutation
import com.apollographql.apollo3.api.Query
import com.apollographql.apollo3.cache.normalized.FetchPolicy
import com.apollographql.apollo3.cache.normalized.apolloStore
import com.apollographql.apollo3.cache.normalized.fetchPolicy
import com.apollographql.apollo3.cache.normalized.normalizedCache
import com.apollographql.apollo3.cache.normalized.sql.SqlNormalizedCacheFactory
import com.apollographql.apollo3.network.okHttpClient
import com.base.andlangcore.util.LogUtils
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import java.util.concurrent.TimeUnit

object SkGqlClient {

    private var apolloClient: ApolloClient? = null

    private val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("apollo.db")

    private val okHttpClient = OkHttpClient.Builder()
        .callTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .followRedirects(false)
        .addInterceptor(HttpLoggingInterceptor().apply {
            setLevel(HttpLoggingInterceptor.Level.BODY)
        })
        .build()

    //https://www.apollographql.com/docs/kotlin/caching/store
    open fun resetClient() {
        HeadsHandle.getHttpDfHeads(true)
        //清除缓存
        apolloClient?.apolloStore?.clearAll()
        //重置请求头
        apolloClient = null
    }


    private fun getClient(): ApolloClient {
        if (apolloClient == null) {
            val url = "https://apollo-fullstack-tutorial.herokuapp.com/graphql"
            apolloClient = ApolloClient.Builder()
                //请求URL
                .serverUrl(url)
                //添加公共请求头
                .httpHeaders(HeadsHandle.getHttpDfHeads(false))
                //拦截401
//                .addHttpInterceptor(AuthorizationInterceptor())
                //日志拦截，使用okhttpclient日志模块
                //.addInterceptor(LoggingApolloInterceptor(url))
                //设置缓存 两种标准策略  内存缓存/sqlite缓存 当前使用为sqlite缓存
//                .normalizedCache(MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024))
                .okHttpClient(okHttpClient)
                .normalizedCache(sqlNormalizedCacheFactory)
                .build()
        }

        return apolloClient!!

    }

    suspend fun <D : Mutation.Data> skMutation(
        mutation: Mutation<D>,
        //是否弹出默认loading
        //mutation请求默认总是使用网络！！！
        //mutation请求默认总是使用网络！！！
        //mutation请求默认总是使用网络！！！
        fetchPolicy: FetchPolicy = FetchPolicy.NetworkOnly
    ): ApolloResponse<D>? {
        try {
            var response = getClient().mutation(mutation)
                .fetchPolicy(fetchPolicy)
                .execute()
            return response
        } catch (exception: Exception) {
            if (BuildConfig.DEBUG) {
                exception.printStackTrace()
            }
            LogUtils.e("${exception.message}")
            return null
        }

    }

    suspend fun <D : Query.Data> skQuery(
        query: Query<D>,
        fetchPolicy: FetchPolicy = FetchPolicy.NetworkOnly
    ): ApolloResponse<D>? {
        try {
            var response = getClient().query(query)
                .fetchPolicy(fetchPolicy)
                .execute()
            return response
        } catch (exception: Exception) {
            if (BuildConfig.DEBUG) {
                exception.printStackTrace()
            }
            LogUtils.e("${exception.message}")
            return null
        }
    }
}